﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "NewLevel.h"
#include "ILevelHeaderTypeBehavior.h"
#include "ILevelType.h"
#include "LevelNameManager.h"
#include "LevelUtils.h"
#include "NewLevelParameterValidator.h"
#include "NewLevelPositionReporterComponent.h"
#include <algorithm>
// 平台相关头文件
#include "AlgorithmProject.h"
#include "AuxiliaryElementUtils.h"
#include "DbObjectUtils.h"
#include "ElementId.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "GbmpDocUtils.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IElementModelShape.h"
#include "IElementOffsetComponent.h"
#include "IElementParameterBindings.h"
#include "IElementParameters.h"
#include "IElementParentReporter.h"
#include "IElementPosition.h"
#include "IElementShapeHandle.h"
#include "IElementViewSpecificShapeComponent.h"
#include "IGenericElement.h"
#include "IGenericType.h"
#include "IGraphicsBRepBody.h"
#include "IGraphicsElementShape.h"
#include "IGraphicsLine.h"
#include "IGraphicsNodeGroup.h"
#include "IGraphicsPlane.h"
#include "IGraphicsStyleManager.h"
#include "IGraphicsText.h"
#include "IInstance.h"
#include "IModelLine.h"
#include "IModelView.h"
#include "IParameter.h"
#include "IParameterBinding.h"
#include "IParameterDefinitionLibrary.h"
#include "IParameterValueElementId.h"

#include "IRegenerator.h"
#include "IRegeneratorDataIdCreator.h"
#include "NewLevelBehaviors.h"
#include "RegenDataId.h"
#include "Vector3dUtils.h"
#include "ImplementationUidTreeRegister.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;

IMPLEMENT_REGEN_FUNCTIONS(gcmp, NewLevel, ReferencePlane)
EXPOSE_DEBUG_MODE(ReplaceBuiltInBehaviorWithNullPointer)
EXPOSE_DEBUG_MODE(ReplaceBuiltInBehaviorWithNullBehavior)

#pragma region 基本属性
DBOBJECT_DATA_DEFINE(NewLevel)
{
    SetOwnerElement(nullptr);
}

gcmp::NdbObject* gcmp::NewLevel::GetTopOwnerObject() const
{
    return quick_cast<NdbObject>(const_cast<IElement*>(GetOwnerElement()));
}

gcmp::UniIdentity gcmp::NewLevel::GetImplementationUid()
{
    static UniIdentity s_implementationUid = UniIdentity::Create(
        GuidUtils::FromString(L"{02FC7110-1314-455C-862E-CFC5ABE10665}"), L"NewLevel");
    return s_implementationUid;
}

IDocument* gcmp::NewLevel::GetDocument() const
{
    if (!m_pOwnerElement)
    {
        return nullptr;
    }
    return m_pOwnerElement->GetDocument();
}

ElementId gcmp::NewLevel::GetOwnerElementId() const
{
    if (!m_pOwnerElement)
    {
        return ElementId::InvalidID;
    }
    return m_pOwnerElement->GetElementId();
}

#pragma endregion 基本属性
#pragma region 关联更新

void gcmp::NewLevel::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
    //参数绑定，并且绑定的不是族参数时
    IElement* pElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"IElement为空",L"GDMPLab",L"2024-03-30");
    IElementParameterBindings* pBehavior = pElement->GetElementParameters()->GetElementParameterBindings();
    if (pBehavior)
    {
        auto& bindingInfos = pBehavior->GetParameterBindings();
        for (int ii = (int)bindingInfos.size(); ii > 0; --ii)
        {
            const IParameterBinding* info = bindingInfos[ii - 1].get();
            IElement* pSourceElement = GetDocument()->GetElement(info->GetSourceElementId());
            if (pSourceElement == nullptr)
            {
                continue;
            }

            IElementParameterBindings* pBingBehavior = pSourceElement->GetElementParameters()->GetElementParameterBindings();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pBingBehavior, L"pBingBehavior无效",L"GDMPLab",L"2024-03-30");

            std::vector<RegenDataId> rcDataIds = pBingBehavior->GetParameterRdIdsByParameterDefinitionId(info->GetSourceParameterDefinitionId());
            std::size_t size = rcDataIds.size();
            if (size > 0 && size != 2) // IFamilyManager为2
            {
                if (deletedElementIds.find(info->GetSourceElementId()) != deletedElementIds.end())
                {
                    pBehavior->DeleteParameterBinding(info->GetTargetParameterDefinitionId());
                }
            }
        }
    }

    //关联视图被删除时
    FOR_EACH(id, deletedElementIds)
    {
        auto it = std::find(GetPlanViewIdsFW__().begin(), GetPlanViewIdsFW__().end(), id);
        if (it != GetPlanViewIdsFW__().end())
        {
            GetPlanViewIdsFW__().erase(it);
        }
    }

    FOR_EACH(id, deletedElementIds)
    {
        auto it = std::find(GetCeilingViewIdsFW__().begin(), GetCeilingViewIdsFW__().end(), id);
        if (it != GetCeilingViewIdsFW__().end())
        {
            GetCeilingViewIdsFW__().erase(it);
        }
    }
}

void gcmp::NewLevel::ReportParents(IElementParentReporter& reporter) const
{
    const IElement* pElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"IElement为空",L"GDMPLab",L"2024-03-30");
    const IElementPosition *posBehavior = pElement->GetElementPosition();
    if (posBehavior != nullptr)
    {
        reporter.ReportStrong(posBehavior->GetBaseAssociatedPlaneId());
    }

    const IElementParameterBindings* pBehavior = GetOwnerElement()->GetElementParameters()->GetElementParameterBindings();
    if (pBehavior)
    {
        auto& bindingInfos = pBehavior->GetParameterBindings();
        FOR_EACH(info, bindingInfos)
        {
            IElement* pSourceElement = GetDocument()->GetElement(info->GetSourceElementId());
            if (pSourceElement != nullptr)
            {
                reporter.ReportWeak(pSourceElement->GetElementId());
            }
        }
    }

    auto& embeddedParamMap = GetOwnerElement()->GetElementParameters()->GetEmbeddedParametersMap();
    FOR_EACH(iter, embeddedParamMap)
    {
        const IParameterValueElementId *pElementIdParamValue = dynamic_cast<const IParameterValueElementId *>(iter.second->GetParameterValueStorage());
        if (pElementIdParamValue != nullptr)
        {
            reporter.ReportWeak(pElementIdParamValue->GetValue());
        }
    }

    reporter.ReportStrong(GetOwnerElement()->GetBasicInformation()->GetTypeId());

    const IGraphicsElementShape* pGrep = pElement->GetElementModelShape()->GetGraphicsElementShape();
    if (pGrep)
    {
        std::vector<ElementId> ids;
        pGrep->GetReferencedElementIds(ids);
        reporter.ReportWeak(ids);
    }

    FOR_EACH(viewId, GetAssociatedPlanViewIds())
    {
        reporter.ReportWeak(viewId);
    }

    FOR_EACH(viewId, GetAssociatedCeilingViewIds())
    {
        reporter.ReportWeak(viewId);
    }

    if (GetBuildingId().IsValid())
    {
        reporter.ReportStrong(GetBuildingId());
    }
}

#pragma endregion 关联更新

#pragma region 其他
bool gcmp::NewLevel::FinishEditing()
{
    std::vector<ElementId> ids = AuxiliaryElementUtils::GetAuxiliaryElements(GetOwnerElement());
    for (int i = 0; i < (int)ids.size(); i++)
    {
        IElement* pElement = GetDocument()->GetElement(ids[i]);
        IElementShapeHandle* pElementShapeHandle = quick_cast<IElementShapeHandle>(pElement);
        if (pElementShapeHandle)
        {
            pElementShapeHandle->FinishEditing();
            continue;
        }
    }
    return true;
}

#pragma endregion 其他

#pragma region protected

bool NewLevel::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;

    if (m_LevelHeaderBehavior)
    {
        m_LevelHeaderBehavior->SetOwnerElement(pOwnerElement);
    }
    return true;
}

#pragma endregion protected


Box3d NewLevel::GetWorkspace(const IDocument* pDoc)
{
    Box3d workSpace;

    // ModelLine
    std::vector<IModelLine*> allModelLines = IModelLine::GetAllModelLines(pDoc);
    FOR_EACH(item, allModelLines)
    {
        if (item->GetOwnerElement()->GetBasicInformation()->GetIsTransient())
            continue;
        const IGraphicsElementShape* pGrep = item->GetOwnerElement()->GetElementModelShape()->GetGraphicsElementShape();
        if (pGrep)
        {
            workSpace.MergeBox(pGrep->GetBox());
        }
    }

    // Instance
    std::vector<IInstance*> allInstances = IInstance::GetAllInstances(pDoc);
    FOR_EACH(item, allInstances)
    {
        if (item->GetBasicInformation()->GetIsTransient())
            continue;
        const IGraphicsElementShape* pGrep = item->GetElementModelShape()->GetGraphicsElementShape();
        if (pGrep)
        {
            workSpace.MergeBox(pGrep->GetBox());
        }
    }

    // Level
    std::vector<IElement*> allLevels = gcmp::GbmpDocUtils::GetElementsByCategory(pDoc, BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION);
    FOR_EACH(item, allLevels)
    {
        if (item->GetBasicInformation()->GetIsTransient())
        {
            continue;
        }

        if (GetOwnerElementId() == item->GetBasicInformation()->GetElementId())
        {
            continue;
        }

        if (IGenericElement* pElement = quick_cast<IGenericElement>(item))
        {
            if (ILevel* pLevel = quick_cast<ILevel>(pElement->GetExternalObject()))
            {
                workSpace.MergeBox(pLevel->GetBox());
                continue;
            }
        }
    }

    return workSpace;
}

NewLevel* NewLevel::Create(IDocument* pDoc, ElementId typeId, const std::wstring& name, const Vector3d& startPt, const Vector3d& endPt, const Vector3d& viewDir, const ElementId &buildingId, ElementCreationOptions eco)
{
    bool isLevelNameExist = LevelUtils::GetLevelIdByName(pDoc, name).IsValid();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(!isLevelNameExist, L"同名的标高已存在，不能创建同名的标高",L"GDMPLab",L"2024-03-30");
    OwnerPtr<NewLevel> opLevel = NEW_AS_OWNER_PTR(NewLevel);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opLevel, L"创建NewLevel失败",L"GDMPLab",L"2024-03-30");

    NewLevel* pLevel = opLevel.get();

    IGenericElement* pGenericElement = IGenericElement::Create(pDoc, TransferOwnership(opLevel), NewLevel::GetClassId().GetGuid(), eco);

    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"创建IGenericElement失败",L"GDMPLab",L"2024-03-30");

    //添加Component
    pGenericElement->SetElementCopyPasteComponent(NEW_AS_OWNER_PTR(NewLevelCopyPasteComponent));
    pGenericElement->SetElementDeletionComponent(NEW_AS_OWNER_PTR(NewLevelDeletionComponent));
    pGenericElement->SetElementTransformationComponent(NEW_AS_OWNER_PTR(NewLevelTransformationComponent));
    pGenericElement->SetViewSpecificShapeComponent(NEW_AS_OWNER_PTR(NewLevelViewSpecificShapeComponent));

    // 创建标高平面及范围框
    Box3d workspace = pLevel->GetWorkspace(pDoc);
    //工作区域获取失败，用默认工作区域
    if (workspace.IsEmpty())
    {
        Vector3d minPoint(-20000.0, -15000.0, 0.0);
        Vector3d maxPoint(20000.0, 15000.0, 0.0);
        workspace.Set(minPoint, maxPoint);
    }
    pLevel->CreateReferencePlane(startPt, endPt, viewDir, workspace);

    // 设置Category
    pGenericElement->GetBasicInformation()->SetCategoryUid(BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION);
    pGenericElement->GetBasicInformation()->SetTypeId(typeId);
    pGenericElement->GetBasicInformation()->SetName(name);
    pGenericElement->GetBasicInformation()->SetImplementationUid(NewLevel::GetImplementationUid());
    if (pGenericElement->GetElementParameters())
        pGenericElement->GetElementParameters()->SetElementParametersCustomizer(NEW_AS_OWNER_PTR(NewLevelParametersCustomizer));
    pGenericElement->SetElementCopyStrategyComponent(NEW_AS_OWNER_PTR(NewLevelCopyStrategyComponent));
    pGenericElement->SetElementPositionReportComponent(NEW_AS_OWNER_PTR(NewLevelPositionReporterComponent));


    // 设置所属的单体
    pLevel->SetbuildingId__(buildingId);

    // 设置标头行为
    const ILevelType *pLevelType = ILevelType::GetLevelType(pDoc, typeId);
    if (pLevelType)
    {
        const ILevelHeaderTypeBehavior* pLevelTypeBehavior = pLevelType->GetCurrentLevelHeaderTypeBehavior();
        if (pLevelTypeBehavior)
        {
            pLevel->SetLevelHeaderBehavior__(pLevelTypeBehavior->CreateLevelHeaderBehavior(pGenericElement));
        }
    }

    if (eco == ElementCreationOptions::Normal)
    {
        auto IsNum = [](wchar_t p) -> bool { return p <= '9' && p >= '0'; };
        if (!name.empty() && IsNum(name.back()))
        {
            int index = (int)name.length() - 2;
            for (; index >= 0; --index)
            {
                wchar_t c = name[index];
                if ((IsNum(c) || c == '-') == false)
                {
                    break;
                }
            }

            std::string subStr = StringUtil::ToString(name.substr(index + 1));
            int number = std::stoi(subStr);
            std::wstring prefix = name.substr(0, index + 1);
            LevelNameManager *pLevelNameMgr = LevelNameManager::Get(pDoc);
            if (pLevelNameMgr)
            {
                pLevelNameMgr->SetPrefix(buildingId, prefix);
                pLevelNameMgr->SetNumber(buildingId, number);
            }
            else
            {
                DBG_WARN(L"标高命名管理为空，应该在文档初始化时就创建好了",L"GDMPLab",L"2024-03-30");
            }
        }
    }

    // 定制视图名称的检查行为
    IElementParameters* pParameterBehavior = pGenericElement->GetElementParameters();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pParameterBehavior, L"pParameterBehavior为空",L"GDMPLab",L"2024-03-30");
    pParameterBehavior->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(NewLevelParameterValidatorOverride, PARAMETER_UID(ElementNameBuiltInParameter)));

    return quick_cast<NewLevel>(pGenericElement->GetExternalObject());
}

std::wstring gcmp::NewLevel::GetName() const
{
    const IElement* pOwnedElement = this->GetOwnerElement();
    DBG_WARN_AND_RETURN_UNLESS(pOwnedElement, L"", L"pOwnedElement为空。",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_UNLESS(pOwnedElement->GetBasicInformation(), L"", L"pOwnedElement->GetBasicInformation()为空。",L"GDMPLab",L"2024-03-30");
    return pOwnedElement->GetBasicInformation()->GetName();
}

NewLevel *gcmp::NewLevel::Create(IDocument *pDoc, ElementId typeId, const LevelName &name, const Vector3d &startPt, const Vector3d &endPt, const Vector3d &viewDir, const ElementId &buildingId, ElementCreationOptions eco)
{
    std::wstring completeName = name.Prefix + StringUtil::ToWString(name.Number) + name.Suffix;
    NewLevel *pLevel = Create(pDoc, typeId, completeName, startPt, endPt, viewDir, buildingId, eco);
    DBG_WARN_AND_RETURN_UNLESS(pLevel, nullptr, L"标高创建失败",L"GDMPLab",L"2024-03-30");

    return pLevel;
}

OwnerPtr<IGraphicsElementShape> NewLevel::CreateLevelGrep(const IModelView* pModelView) const
{
    Vector3d startPoint, endPoint;
    GetModelViewProjectLine(pModelView, startPoint, endPoint);

    // 标高线
    OwnerPtr<IGraphicsElementShape> opLevelGRep = IGraphicsElementShape::Create(GraphicsRenderLayer::Annotation);
    OwnerPtr<IGraphicsLine> curElevLine = IGraphicsLine::Create(startPoint, endPoint);
    curElevLine->SetId(GraphicsNodeId(1));
    opLevelGRep->AddChild(TransferOwnership(curElevLine));

    const ILevelType* pLevelType = GetLevelType();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pLevelType, L"当前标高类型不存在？",L"GDMPLab",L"2024-03-30");

    // 创建标高的Header
    double zHeight = GetElevation() / 1000.0;
    double viewScale = pModelView->GetViewScale();
    Vector3d viewRightDir = pModelView->GetRightDirection();
    Vector3d levelDir = IsShowFromLeftToRight() ? viewRightDir : -viewRightDir;
    bool startSymbol = pLevelType->IsStartHeaderVisible();
    if (startSymbol)
    {
        OwnerPtr<IGraphicsNodeGroup> opStartSymbol = CreateLevelHeader(startPoint, -levelDir, viewRightDir, zHeight, viewScale);
        opLevelGRep->AddChild(TransferOwnership(opStartSymbol));
    }

    bool endSymbol = pLevelType->IsEndHeaderVisible();
    if (endSymbol)
    {
        OwnerPtr<IGraphicsNodeGroup> opEndSymbol = CreateLevelHeader(endPoint, levelDir, viewRightDir, zHeight, viewScale);
        opLevelGRep->AddChild(TransferOwnership(opEndSymbol));
    }

    return opLevelGRep;
}

double NewLevel::GetElevation() const
{
    const IPlane* pPlane = GetReferencePlane();
    DBG_WARN_AND_RETURN_UNLESS(pPlane, 0.0, L"当前标高平面不存在？",L"GDMPLab",L"2024-03-30");

    return pPlane->GetOrigin().Z();
}

bool NewLevel::SetElevation(double elevation)
{
    IPlane* refPlane = GetReferencePlaneFW();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(refPlane, L"refPlane为空",L"GDMPLab",L"2024-03-30");
    refPlane->SetOrigin(Vector3d(refPlane->GetOrigin().Vec2d(), elevation));
    MarkReferencePlaneRdId();
    return true;
}

gcmp::Box3d NewLevel::GetBox() const
{
    gcmp::Box3d box;

    const IPlane* pPlane = GetReferencePlane();
    DBG_WARN_AND_RETURN_UNLESS(pPlane, box, L"ReferencePlane不存在",L"GDMPLab",L"2024-03-30");

    double length = GetLevelPlaneLength();
    double depth = GetLevelPlaneDepth();
    if (MathUtils::IsGreaterThan(length, 0.0, Constants::DOUBLE_EPS) && MathUtils::IsGreaterThan(depth, 0.0, Constants::DOUBLE_EPS))
    {
        Vector3d p1, p2, p3, p4;
        GetLevelPlaneCorner(p1, p2, p3, p4);
        box.MergePoint(p1);
        box.MergePoint(p2);
        box.MergePoint(p3);
        box.MergePoint(p4);
    }
    return box;
}

// 下面创建标高平面和范围，生成GRep使用了原来的逻辑，目前只为能生成及显示，后续需要根据新的数据结构更新
bool NewLevel::CreateReferencePlane(const Vector3d& startPt, const Vector3d& endPt, const Vector3d& viewDir, const Box3d& workspace)
{
    // 标高平面高度、宽度
    Vector3d lineMiddlePnt = (startPt + endPt) / 2.0;
    double height = lineMiddlePnt.Z();
    double length = Vector3dUtils::Distance(startPt, endPt);

    // 标高面X轴方向
    Vector3d lineDir = endPt - startPt;
    Vector3d viewRightDir = viewDir.Cross(Vector3d::UnitZ);
    viewRightDir.Normalize();
    Vector2d rightDir(viewRightDir.X(), viewRightDir.Y());

    // 标高面深度
    Vector3d minPnt = workspace.GetMinPoint();
    Vector3d maxPnt = workspace.GetMaxPoint();

    Vector3d p1(minPnt.X(), minPnt.Y(), height);
    Vector3d p2(minPnt.X(), maxPnt.Y(), height);
    Vector3d p3(maxPnt.X(), maxPnt.Y(), height);
    Vector3d p4(maxPnt.X(), minPnt.Y(), height);

    Vector3d v1 = p1 - lineMiddlePnt;
    Vector3d v2 = p2 - lineMiddlePnt;
    Vector3d v3 = p3 - lineMiddlePnt;
    Vector3d v4 = p4 - lineMiddlePnt;

    double dis1 = v1.Dot(viewDir);
    double maxVal = dis1;
    double minVal = dis1;

    double dis2 = v2.Dot(viewDir);
    if (MathUtils::IsGreaterThan(dis2, maxVal, Constants::DOUBLE_EPS))
    {
        maxVal = dis2;
    }
    else if (MathUtils::IsLessThan(dis2, minVal, Constants::DOUBLE_EPS))
    {
        minVal = dis2;
    }

    double dis3 = v3.Dot(viewDir);
    if (MathUtils::IsGreaterThan(dis3, maxVal, Constants::DOUBLE_EPS))
    {
        maxVal = dis3;
    }
    else if (MathUtils::IsLessThan(dis3, minVal, Constants::DOUBLE_EPS))
    {
        minVal = dis3;
    }

    double dis4 = v4.Dot(viewDir);
    if (MathUtils::IsGreaterThan(dis4, maxVal, Constants::DOUBLE_EPS))
    {
        maxVal = dis4;
    }
    else if (MathUtils::IsLessThan(dis4, minVal, Constants::DOUBLE_EPS))
    {
        minVal = dis4;
    }

    Vector3d maxDisPnt = lineMiddlePnt + maxVal * viewDir;
    Vector3d minDisPnt = lineMiddlePnt + minVal * viewDir;
    Vector3d planeMidPnt = (maxDisPnt + minDisPnt) / 2.0;
    double depth = std::abs(maxVal) + std::abs(minVal);

    Vector3d origin = Vector3d(planeMidPnt.Vec2d(), height);
    Vector3d dirX = viewRightDir;
    dirX.Normalize();
    Vector3d dirY = Vector3d::UnitZ.Cross(dirX);
    TerminalParams terminalParams = Vector3dUtils::GetAngle(viewRightDir, lineDir) < Constants::DOUBLE_EPS
        ? TerminalParams::Create(-length / 2, 0, length / 2, -depth / 2, 0, depth / 2)
        : TerminalParams::Create(length / 2, 0, -length / 2, -depth / 2, 0, depth / 2);

    if (Vector3dUtils::GetAngle(viewRightDir, lineDir) < Constants::DOUBLE_EPS)
    {
        SetIsShowFromLeftToRight__(true);
    }
    else
    {
        SetIsShowFromLeftToRight__(false);
    }

    //初始化参考平面
    OwnerPtr<IPlane> refPlane = IPlane::Create(origin, dirX, dirY);
    SetReferencePlane__(TransferOwnership(refPlane));
    SetGlobalTerminalParams__(terminalParams);

    return true;
}

double NewLevel::GetLevelPlaneLength() const 
{
    bool bSameDirection = false;
    return GetGlobalTerminalParams().GetRangeU(bSameDirection).Length();
}

double NewLevel::GetLevelPlaneDepth() const 
{
    bool bSameDirection = false;
    return GetGlobalTerminalParams().GetRangeV(bSameDirection).Length();
}

void NewLevel::GetLevelPlaneCorner(Vector3d& bottomLeft, Vector3d& bottomRight, Vector3d& topLeft, Vector3d& topRight) const
{
    const IPlane* modelPlane = GetReferencePlane();
    DBG_WARN_AND_RETURN_VOID_UNLESS(modelPlane, L"modelPlane不存在",L"GDMPLab",L"2024-03-30");

    const Vector2d& midPnt = GetMidPoint();
    const Vector2d& rightDir = modelPlane->GetDirectionU().Vec2d();
    double height = GetElevation();
    double length = GetLevelPlaneLength();
    double depth = GetLevelPlaneDepth();
    DBG_WARN_AND_RETURN_VOID_UNLESS(length >= Constants::DOUBLE_EPS, L"当前标高平面长度参数不合理",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_VOID_UNLESS(depth >= Constants::DOUBLE_EPS, L"当前标高平面深度参数不合理",L"GDMPLab",L"2024-03-30");

    Vector3d xdir = Vector3d(rightDir.X(), rightDir.Y(), 0.0);
    Vector3d dir = Vector3d::UnitZ.Cross(xdir);

    bottomLeft = Vector3d(midPnt, height) - dir * depth / 2.0 - xdir * length / 2.0;
    bottomRight = Vector3d(midPnt, height) - dir * depth / 2.0 + xdir * length / 2.0;
    topLeft = Vector3d(midPnt, height) + dir * depth / 2.0 - xdir * length / 2.0;
    topRight = Vector3d(midPnt, height) + dir * depth / 2.0 + xdir * length / 2.0;
}


void NewLevel::GetModelViewProjectLine(const IModelView* pModelView, Vector3d& start, Vector3d& end) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"pModelView不能为空",L"GDMPLab",L"2024-03-30");
    Vector3d viewRightDir = pModelView->GetRightDirection();
    DBG_WARN_AND_RETURN_VOID_UNLESS(viewRightDir.IsUnit(), L"请使用单位化向量",L"GDMPLab",L"2024-03-30");

    // 通过标高面投影到视图面，计算标高线
    double height = GetElevation();

    const IPlane* modelPlane = GetReferencePlane();
    DBG_WARN_AND_RETURN_VOID_UNLESS(modelPlane, L"modelPlane不存在",L"GDMPLab",L"2024-03-30");
    Vector3d midPnt(GetMidPoint(), height);
    Vector3d p1, p2, p3, p4;
    GetLevelPlaneCorner(p1, p2, p3, p4);

    OwnerPtr<IPlane> pViewPlane = pModelView->GetWorkPlane();

    Vector2d uvParameter;
    Vector3d midPntProj;
    AlgorithmProject::Project(midPnt, pViewPlane.get(), uvParameter, midPntProj);
    Vector3d p1Proj;
    AlgorithmProject::Project(p1, pViewPlane.get(), uvParameter, p1Proj);
    Vector3d p2Proj;
    AlgorithmProject::Project(p2, pViewPlane.get(), uvParameter, p2Proj);
    Vector3d p3Proj;
    AlgorithmProject::Project(p3, pViewPlane.get(), uvParameter, p3Proj);
    Vector3d p4Proj;
    AlgorithmProject::Project(p4, pViewPlane.get(), uvParameter, p4Proj);


    Vector3d v1 = p1Proj - midPntProj;
    Vector3d v2 = p2Proj - midPntProj;
    Vector3d v3 = p3Proj - midPntProj;
    Vector3d v4 = p4Proj - midPntProj;

    double dis1 = v1.Dot(viewRightDir);
    double maxVal = dis1;
    double minVal = dis1;

    double dis2 = v2.Dot(viewRightDir);
    if (MathUtils::IsGreaterThan(dis2, maxVal, Constants::DOUBLE_EPS))
    {
        maxVal = dis2;
    }
    else if (MathUtils::IsLessThan(dis2, minVal, Constants::DOUBLE_EPS))
    {
        minVal = dis2;
    }

    double dis3 = v3.Dot(viewRightDir);
    if (MathUtils::IsGreaterThan(dis3, maxVal, Constants::DOUBLE_EPS))
    {
        maxVal = dis3;
    }
    else if (MathUtils::IsLessThan(dis3, minVal, Constants::DOUBLE_EPS))
    {
        minVal = dis3;
    }

    double dis4 = v4.Dot(viewRightDir);
    if (MathUtils::IsGreaterThan(dis4, maxVal, Constants::DOUBLE_EPS))
    {
        maxVal = dis4;
    }
    else if (MathUtils::IsLessThan(dis4, minVal, Constants::DOUBLE_EPS))
    {
        minVal = dis4;
    }

    Vector3d maxDisPnt = midPntProj + maxVal * viewRightDir;
    Vector3d minDisPnt = midPntProj + minVal * viewRightDir;
    start = IsShowFromLeftToRight() ? minDisPnt : maxDisPnt;
    end = IsShowFromLeftToRight() ? maxDisPnt : minDisPnt;
}

OwnerPtr<IGraphicsNodeGroup> NewLevel::CreateLevelHeader(const Vector3d& symbolPos, const Vector3d& symbolDir, const Vector3d& texDir, double height, double viewScale) const
{
    if (m_LevelHeaderBehavior)
    {
        return m_LevelHeaderBehavior->CreateLevelHeader(symbolPos, symbolDir, texDir, height, viewScale);
    }

    return nullptr;
}

const ILevelType* NewLevel::GetLevelType() const
{
    const IGenericElement* pOwnerElement = quick_cast<IGenericElement>(GetOwnerElement());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pOwnerElement, L"当前标高不存在？",L"GDMPLab",L"2024-03-30");

    const IGenericType* pGenericType = quick_cast<IGenericType>(pOwnerElement->GetBasicInformation()->GetType());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericType, L"当前标高类型不存在？",L"GDMPLab",L"2024-03-30");

    return ILevelType::GetLevelType(GetDocument(), pGenericType->GetElementId());
}

bool NewLevel::MoveAuxiliaryPoint(const IModelView* pModelView, const Vector3d newPoint, ElementId shapeHandleId)
{
    DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, false, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_UNLESS(newPoint.IsValid(), false, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(GetDocument()->GetElement(shapeHandleId));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pShapeHandle != nullptr, L"没获取辅助点",L"GDMPLab",L"2024-03-30");

    const NewLevelShapeHandleBehavior* pShapeHandleBehavior = quick_cast<const NewLevelShapeHandleBehavior>(pShapeHandle->GetElementShapeHandleBehavior());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pShapeHandleBehavior, L"没获取辅助点的行为",L"GDMPLab",L"2024-03-30");

    NewLevelShapeElementPosition position = pShapeHandleBehavior->GetPosition();

    Vector3d startPnt, endPnt;
    this->GetModelViewProjectLine(pModelView, startPnt, endPnt);
    Vector3d movePoint = position == NewLevelShapeElementPosition::Left ? startPnt : endPnt;
    const IPlane* pModelPlane = GetReferencePlane();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelPlane, L"modelPlane不存在",L"GDMPLab",L"2024-03-30");

    Vector3d levelRightDir(pModelPlane->GetDirectionU().Vec2d(), 0.0);
    Vector3d levelDir = Vector3d::UnitZ.Cross(levelRightDir);
    Vector2d midPnt = GetMidPoint();
    double length = GetLevelPlaneLength();
    double depth = GetLevelPlaneDepth();

    Vector3d viewDir = pModelView->GetViewDirection();
    Vector3d moveVec = newPoint - movePoint;
    // Length，Depth的变化需要根据比率来定
    double detLenth = moveVec.Dot(levelRightDir);
    double levelRightRatio = fabs((endPnt - startPnt).Dot(levelRightDir));
    if (MathUtils::IsZero(levelRightRatio) == false)
    {
        detLenth = detLenth * length / levelRightRatio;
    }
    double detDepth = moveVec.Dot(levelDir);
    double levelRatio = fabs((endPnt - startPnt).Dot(levelDir));
    if (MathUtils::IsZero(levelRatio) == false)
    {
        detDepth = detDepth * depth / levelRatio;
    }

    Vector3d bottomLeft, bottomRight, topLeft, topRight;
    this->GetLevelPlaneCorner(bottomLeft, bottomRight, topLeft, topRight);
    Vector3d v1 = bottomLeft - movePoint;
    Vector3d v2 = bottomRight - movePoint;
    Vector3d v3 = topLeft - movePoint;
    Vector3d v4 = topRight - movePoint;

    //设置新参数
    double newDepth = depth;
    double newLength = length;
    if (Vector3dUtils::IsParallel(v1, viewDir))  //拖拽点是bottomLeft
    {
        newDepth = depth - detDepth;
        newLength = length - detLenth;
    }
    else if (Vector3dUtils::IsParallel(v2, viewDir)) //拖拽点是bottomRight
    {
        newDepth = depth - detDepth;
        newLength = length + detLenth;
    }
    else if (Vector3dUtils::IsParallel(v3, viewDir)) //拖拽点是topLeft
    {
        newDepth = depth + detDepth;
        newLength = length - detLenth;
    }
    else if (Vector3dUtils::IsParallel(v4, viewDir)) //拖拽点是topRight
    {
        newDepth = depth + detDepth;
        newLength = length + detLenth;
    }
    else
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(false, L"没有计算出拖拽哪个点",L"GDMPLab",L"2024-03-30");
    }

    if (MathUtils::IsEqual(newDepth, 0.0, Constants::DOUBLE_EPS) || MathUtils::IsEqual(newLength, 0.0, Constants::DOUBLE_EPS))
        return false;

    if (newDepth < 0.0 || newLength < 0.0)
    {
        this->SetShowFromLeftToRight(!this->IsShowFromLeftToRight());
    }

    double newMiddleU = GetGlobalTerminalParams().GetMidRangeU() + detLenth / 2;
    double newMiddleV = GetGlobalTerminalParams().GetMidRangeV() + detDepth / 2;
    SetGlobalTerminalParams__(TerminalParams::Create(newMiddleU - newLength / 2, newMiddleU, newMiddleU + newLength / 2, newMiddleV - newDepth / 2, newMiddleV, newMiddleV + newDepth / 2));

    return true;
}

Vector2d NewLevel::GetMidPoint() const
{
    const IPlane* pPlane = GetReferencePlane();
    DBG_WARN_AND_RETURN_UNLESS(pPlane, Vector2d(), L"modelPlane不存在",L"GDMPLab",L"2024-03-30");

    return pPlane->GetPoint(GetGlobalTerminalParams().GetMidRangeU(), GetGlobalTerminalParams().GetMidRangeV()).Vec2d();
}

bool NewLevel::AddAssociatedPlanViewId(ElementId viewId)
{
    GetPlanViewIdsFW__().push_back(viewId);
    return true;
}

bool NewLevel::AddAssociatedCeilingViewId(ElementId viewId)
{
    GetCeilingViewIdsFW__().push_back(viewId);
    return true;
}

std::vector<ElementId> NewLevel::GetAssociatedPlanViewIds() const
{
    return GetPlanViewIds__();
}

std::vector<ElementId> NewLevel::GetAssociatedCeilingViewIds() const
{
    return GetCeilingViewIds__();
}

bool NewLevel::Translate(const IElementMoveContext& moveContext)
{
    const IPlane* pModelPlane = GetReferencePlane();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelPlane, L"modelPlane不存在",L"GDMPLab",L"2024-03-30");

    double levelHeight = GetElevation() + moveContext.GetMoveVector().Z();
    SetElevation(levelHeight);

    Vector2d levelUDir = pModelPlane->GetDirectionU().Vec2d();
    levelUDir.Normalize();
    Vector2d levelVDir = pModelPlane->GetDirectionV().Vec2d();
    levelVDir.Normalize();

    double moveU = moveContext.GetMoveVector().Vec2d().Dot(levelUDir);
    double moveV = moveContext.GetMoveVector().Vec2d().Dot(levelVDir);
    const TerminalParams& params = GetGlobalTerminalParams();
    SetGlobalTerminalParams__(TerminalParams::Create(params.GetStartRangeU() + moveU, params.GetMidRangeU() + moveU, params.GetEndRangeU() + moveU,
        params.GetStartRangeV() + moveV, params.GetMidRangeV() + moveV, params.GetEndRangeV() + moveV));

    return true;
}

OwnerPtr<IGraphicsElementShape> NewLevel::CreateLevelGrepIn3DView(const IModelView* pModelView) const
{
    OwnerPtr<IGraphicsElementShape> outputGrep = IGraphicsElementShape::Create(GraphicsRenderLayer::Annotation);
    const IPlane* zeroHeightBoundedModelPlane = GetReferencePlane();
    Vector3d origin(zeroHeightBoundedModelPlane->GetOrigin().Vec2d(), GetElevation());
    
    ElementId gstyleId = GetDocument()->GetGraphicsStyleManager()->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION);
    bool sameDirection = false;
    OwnerPtr<IGraphicsPlane> graphicsPlane = IGraphicsPlane::CreateByDirections(origin, zeroHeightBoundedModelPlane->GetDirectionU(), zeroHeightBoundedModelPlane->GetDirectionV());
    graphicsPlane->SetLimits(GetGlobalTerminalParams().GetRangeU(sameDirection), GetGlobalTerminalParams().GetRangeV(sameDirection));
    graphicsPlane->SetId(GraphicsNodeId(1));
    graphicsPlane->SetGraphicsStyleId(gstyleId);
    outputGrep->AddChild(TransferOwnership(graphicsPlane));
    return outputGrep;
}

std::set<std::pair<double, gcmp::ElementId>> NewLevelUtil::GetAllLevelsFromLowToHigh(const gcmp::IDocument* pDoc)
{
    std::set<std::pair<double, ElementId>> levelSet;
    std::vector<gcmp::IElement*> levels = gcmp::GbmpDocUtils::GetElementsByCategory(pDoc, gcmp::BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION);
    FOR_EACH(item, levels)
    {
        gcmp::IGenericElement* pGenericElement = gcmp::quick_cast<gcmp::IGenericElement>(item);
        if (nullptr == pGenericElement)
            continue;

        gcmp::NewLevel* pNewLevel = gcmp::quick_cast<gcmp::NewLevel>(pGenericElement->GetExternalObject());
        if (nullptr == pNewLevel)
            continue;

        std::pair<double, ElementId> val(pNewLevel->GetElevation(), pNewLevel->GetOwnerElement()->GetBasicInformation()->GetElementId());
        levelSet.insert(val);
    }
    return levelSet;
}

REGISTER_IMPLEMENTATION_UID_TREE_RELATION(IGenericElement, NewLevel);
